package windbell.domain.risk.impl;

import com.google.common.base.Objects;
import com.uniquesoft.uidl.validation.Validates;
import edu.fudan.langlab.domain.statemachine.ModelObjectLogService;
import edu.fudan.mylang.pf.BaseModelObject;
import edu.fudan.mylang.pf.IObjectFactory;
import edu.fudan.mylang.utils.DateUtil;
import java.util.Collection;
import java.util.Date;
import javax.persistence.CascadeType;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.eclipse.xtext.xbase.lib.Functions.Function1;
import org.eclipse.xtext.xbase.lib.IterableExtensions;
import org.eclipse.xtext.xbase.lib.ObjectExtensions;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
import org.hibernate.annotations.DiscriminatorOptions;
import windbell.domain.risk.RiskCheck;
import windbell.domain.risk.RiskCheckItem;
import windbell.domain.risk.RiskCheckSource;
import windbell.domain.risk.RiskCheckStatus;
import windbell.domain.risk.RiskCheckTarget;
import windbell.domain.risk.RiskCheckTemplate;
import windbell.domain.risk.RiskCheckTemplateItem;
import windbell.domain.risk.impl.RiskCheckItemImpl;
import windbell.domain.risk.impl.RiskCheckSourceImpl;
import windbell.domain.risk.impl.RiskCheckTargetImpl;
import windbell.domain.risk.proxy.RiskCheckProxy;

@Entity
@DiscriminatorValue("RISKCHECK_TYPE")
@DiscriminatorOptions(force = true)
@DiscriminatorColumn(length = 64)
@Table(name = "riskcheck")
public class RiskCheckImpl extends BaseModelObject implements RiskCheck {
  public RiskCheckImpl() {
    super();
  }
  
  private RiskCheckStatus Status;
  
  public RiskCheckStatus getStatus() {
    return this.Status;
  }
  
  private ModelObjectLogService getModelObjectLogService() {
    return getBeanFactory().getBean(ModelObjectLogService.class);
  }
  
  private void _start() {
    
    Status=RiskCheckStatus.created;
  }
  
  public void start() {
    if(Status==null){
    	_start();
    	getModelObjectLogService().createLog(this,"Status","Start");
    	getBeanFactory().getBean(windbell.domain.risk.events.RiskCheckEventsManager.class).fireStarted(this);					
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException("allready started");
    }
  }
  
  private void _createItemsFromTemplate(final RiskCheckTemplate template) {
    
    Collection<RiskCheckTemplateItem> _checkList = template.getCheckList();
    final Procedure1<RiskCheckTemplateItem> _function = new Procedure1<RiskCheckTemplateItem>() {
        public void apply(final RiskCheckTemplateItem templateItem) {
          RiskCheckItem _createAndAddtoCheckItems = RiskCheckImpl.this.createAndAddtoCheckItems();
          final Procedure1<RiskCheckItem> _function = new Procedure1<RiskCheckItem>() {
              public void apply(final RiskCheckItem it) {
                it.setCheckItem(templateItem);
              }
            };
          ObjectExtensions.<RiskCheckItem>operator_doubleArrow(_createAndAddtoCheckItems, _function);
        }
      };
    IterableExtensions.<RiskCheckTemplateItem>forEach(_checkList, _function);
    Status=RiskCheckStatus.created;
  }
  
  public void createItemsFromTemplate(final RiskCheckTemplate template) {
    if(Status==RiskCheckStatus.created){
    	_createItemsFromTemplate(template);
    	getModelObjectLogService().createLog(this,"Status","createItemsFromTemplate");
    	getBeanFactory().getBean(windbell.domain.risk.events.RiskCheckEventsManager.class).fireCreateItemsFromTemplate(this,template);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _publish(final Date date) {
    
    this.startDate = date;
    final Procedure1<RiskCheckItem> _function = new Procedure1<RiskCheckItem>() {
        public void apply(final RiskCheckItem it) {
          it.publish();
          it.startAudit();
        }
      };
    IterableExtensions.<RiskCheckItem>forEach(this.checkItems, _function);
    Status=RiskCheckStatus.checking;
  }
  
  public void publish(final Date date) {
    if(Status==RiskCheckStatus.created){
    	_publish(date);
    	getModelObjectLogService().createLog(this,"Status","publish");
    	getBeanFactory().getBean(windbell.domain.risk.events.RiskCheckEventsManager.class).firePublish(this,date);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _$itemFinished() {
    
    final Function1<RiskCheckItem,Boolean> _function = new Function1<RiskCheckItem,Boolean>() {
        public Boolean apply(final RiskCheckItem it) {
          Boolean _isFinished = it.isFinished();
          return _isFinished;
        }
      };
    boolean _forall = IterableExtensions.<RiskCheckItem>forall(this.checkItems, _function);
    if (_forall) {
      Date _day = DateUtil.today();
      this.finishDate = _day;
      Status=RiskCheckStatus.finished;
    } else {
    }
  }
  
  public void $itemFinished() {
    if(Status==RiskCheckStatus.checking){
    	_$itemFinished();
    	getModelObjectLogService().createLog(this,"Status","$itemFinished");
    	getBeanFactory().getBean(windbell.domain.risk.events.RiskCheckEventsManager.class).fire$itemFinished(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  public Boolean isCreated() {
    return windbell.domain.risk.RiskCheckStatus.created==Status;
  }
  
  public Boolean isChecking() {
    return windbell.domain.risk.RiskCheckStatus.checking==Status;
  }
  
  public Boolean isFinished() {
    return windbell.domain.risk.RiskCheckStatus.finished==Status;
  }
  
  @JoinColumn(name = "checkTarget_id")
  @ManyToOne(targetEntity = RiskCheckTargetImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
  private RiskCheckTarget checkTarget;
  
  public RiskCheckTarget getCheckTarget() {
    return this.checkTarget;
  }
  
  public RiskCheck setCheckTarget(final RiskCheckTarget checkTarget) {
    this.checkTarget = checkTarget;
    return this;			
    
  }
  
  @JoinColumn(name = "source_id")
  @ManyToOne(targetEntity = RiskCheckSourceImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
  private RiskCheckSource source;
  
  public RiskCheckSource getSource() {
    return this.source;
  }
  
  public RiskCheck setSource(final RiskCheckSource source) {
    this.source = source;
    return this;			
    
  }
  
  @OneToMany(targetEntity = RiskCheckItemImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE }, mappedBy = "riskCheck")
  private Collection<RiskCheckItem> checkItems = new java.util.ArrayList<windbell.domain.risk.RiskCheckItem>();;
  
  public Collection<RiskCheckItem> getCheckItems() {
    return this.checkItems;
  }
  
  public RiskCheckItem createAndAddtoCheckItems() {
    getCheckItems().size();
    windbell.domain.risk.RiskCheckItem riskCheckItem = new windbell.domain.risk.impl.RiskCheckItemImpl(this);
    getObjectFactory().create(riskCheckItem);
    getCheckItems().add(riskCheckItem);
    riskCheckItem.start();
    return riskCheckItem;
    
  }
  
  public RiskCheckItem createAndAddtoCheckItems(final Procedure1<RiskCheckItem> updater) {
    getCheckItems().size();
    windbell.domain.risk.RiskCheckItem riskCheckItem = new windbell.domain.risk.impl.RiskCheckItemImpl(this);
    getObjectFactory().create(riskCheckItem);
    getCheckItems().add(riskCheckItem);
    updater.apply(riskCheckItem);
    riskCheckItem.start();
    return riskCheckItem;
    
  }
  
  public RiskCheck removeAllCheckItems() {
    for(RiskCheckItem obj : this.checkItems){
    	getObjectFactory().delete(obj);
    }
    this.checkItems.clear();
    return this;	
    
  }
  
  public RiskCheck removeFromCheckItems(final RiskCheckItem riskCheckItem) {
    this.checkItems.remove(riskCheckItem);
    getObjectFactory().delete(riskCheckItem);
    return this;
    
  }
  
  private Date startDate;
  
  public Date getStartDate() {
    return this.startDate;
  }
  
  public RiskCheck setStartDate(final Date startDate) {
    this.startDate = startDate;
    return this;			
    
  }
  
  private Date dueDate;
  
  public Date getDueDate() {
    return this.dueDate;
  }
  
  public RiskCheck setDueDate(final Date dueDate) {
    this.dueDate = dueDate;
    return this;			
    
  }
  
  private Date finishDate;
  
  public Date getFinishDate() {
    return this.finishDate;
  }
  
  public RiskCheck setFinishDate(final Date finishDate) {
    this.finishDate = finishDate;
    return this;			
    
  }
  
  public void checkValid() {
    boolean _notEquals = (!Objects.equal(this.checkTarget, null));
    Validates.Assert(_notEquals, "\u5FC5\u987B\u8BBE\u7F6E\u68C0\u67E5\u5BF9\u8C61");
    boolean _notEquals_1 = (!Objects.equal(this.source, null));
    Validates.Assert(_notEquals_1, "\u5FC5\u987B\u8BBE\u7F6E\u6765\u6E90");
  }
  
  public static RiskCheck create(final IObjectFactory objectFactory) {
    windbell.domain.risk.RiskCheck riskCheck = new windbell.domain.risk.impl.RiskCheckImpl(
    );
    objectFactory.create(riskCheck);
    riskCheck.start();
    return riskCheck;			
    
  }
  
  public static RiskCheck createRiskCheckImpl(final IObjectFactory objectFactory, final Procedure1<RiskCheck> init) {
    windbell.domain.risk.RiskCheck riskCheck = new windbell.domain.risk.impl.RiskCheckImpl(
    );
    objectFactory.create(riskCheck);
    init.apply(riskCheck);
    riskCheck.start();
    return riskCheck;			
    
  }
  
  public RiskCheckProxy toProxy() {
    windbell.domain.risk.proxy.RiskCheckProxy proxy = new windbell.domain.risk.proxy.RiskCheckProxy();
    proxy.setId(this.getId());
    if(this instanceof edu.fudan.mylang.pf.INamedModelObject){
    	proxy.setName(((edu.fudan.mylang.pf.INamedModelObject)this).getEntityName());
    }
    proxy.setStatus(this.getStatus().name());
    return proxy;
    
  }
}
